﻿using System;
using System.Collections.Generic;
using ZFramework.Runtime;

namespace ZGame
{
    public class EntityLoader : IReference
    {
        public object Owner { get; private set; }

        public EntityLoader()
        {
            dicSerial2Entity = new Dictionary<int, Entity>();
            dicCallback = new Dictionary<int, Action<Entity>>();
            tempList = new List<int>();
            _tempEntities = new List<Entity>();
            Owner = null;
        }

        // public int ShowEntity(int cfgId, Action<Entity> onShowSuccess, object userData = null)
        // {
        //     var dataEntity = GameEntry.dataManager.GetData<DataEntity>();
        //     var entityInfo = dataEntity.GetEntityInfo(cfgId);
        //     if (entityInfo == null)
        //     {
        //         Log.Error("找不到cfgId=={0}的entity信息", cfgId);
        //         return 0;
        //     }
        //
        //     int serialId = GameEntry.entityMgr.GenerateSerialId();
        //     dicCallback.Add(serialId, onShowSuccess);
        //
        //     GameEntry.entityMgr.ShowEntity(serialId, entityInfo.LogicType, entityInfo.AssetPath, entityInfo.GroupName,
        //         1, userData);
        //     return serialId;
        // }

        public bool HasEntity(int serialId)
        {
            return GetEntity(serialId) != null;
        }

        public Entity GetEntity(int serialId)
        {
            if (dicSerial2Entity.ContainsKey(serialId))
            {
                return dicSerial2Entity[serialId];
            }

            return null;
        }

        public IEnumerable<Entity> GetAllEntities()
        {
            return dicSerial2Entity.Values;
        }

        public void HideEntity(int serialId)
        {
            Entity entity = null;
            if (!dicSerial2Entity.TryGetValue(serialId, out entity))
            {
                Log.Error("Cannot  find entity('serial id:{0}') ", serialId);
                return;
            }

            dicSerial2Entity.Remove(serialId);
            dicCallback.Remove(serialId);

            _tempEntities.Clear();
            var entities = _tempEntities;
            GameEntry.entityMgr.GetChildEntities(entity.Id, entities);
            foreach (var item in entities)
            {
                //若Child Entity由这个Loader对象托管，则由此Loader释放
                if (dicSerial2Entity.ContainsKey(item.Id))
                {
                    HideEntity(item);
                }
                else //若Child Entity不由这个Loader对象托管，则从Parent Entity脱离
                    GameEntry.entityMgr.DetachEntity(item.Id);
            }

            GameEntry.entityMgr.HideEntity(entity.Id);
        }

        public void HideEntity(Entity entity)
        {
            if (entity == null)
                return;

            HideEntity(entity.Id);
        }

        public void HideAllEntity()
        {
            tempList.Clear();

            foreach (var entity in dicSerial2Entity.Values)
            {
                Entity parentEntity = GameEntry.entityMgr.GetParentEntity(entity.Id);
                //有ParentEntity
                if (parentEntity != null)
                {
                    //若Parent Entity由这个Loader对象托管，则把这个Child Entity从数据中移除，在隐藏Parent Entity，GF内部会处理Child Entity
                    if (dicSerial2Entity.ContainsKey(parentEntity.Id))
                    {
                        dicSerial2Entity.Remove(entity.Id);
                        dicCallback.Remove(entity.Id);
                    }
                    //若Parent Entity不由这个Loader对象托管，则从Parent Entity脱离
                    else
                    {
                        GameEntry.entityMgr.DetachEntity(entity.Id);
                    }
                }
            }

            foreach (var serialId in dicSerial2Entity.Keys)
            {
                tempList.Add(serialId);
            }

            foreach (var serialId in tempList)
            {
                HideEntity(serialId);
            }

            dicSerial2Entity.Clear();
            dicCallback.Clear();
        }

        private void OnShowEntitySuccess(object sender, GameEventArgs e)
        {
            ShowEntitySuccessEventArgs ne = (ShowEntitySuccessEventArgs) e;
            if (ne == null)
            {
                return;
            }

            Action<Entity> callback = null;
            if (!dicCallback.TryGetValue(ne.Entity.Id, out callback))
            {
                return;
            }

            dicSerial2Entity.Add(ne.Entity.Id, ne.Entity);
            callback?.Invoke(ne.Entity);
        }

        private void OnShowEntityFail(object sender, GameEventArgs e)
        {
            ShowEntityFailureEventArgs ne = (ShowEntityFailureEventArgs) e;
            if (ne == null)
            {
                return;
            }

            if (dicCallback.ContainsKey(ne.EntityId))
            {
                dicCallback.Remove(ne.EntityId);
                Log.Warning("Show entity failure with error message '{0}'.", ne.ErrorMessage);
            }
        }

        public static EntityLoader Create(object owner)
        {
            EntityLoader entityLoader = ReferencePool.Acquire<EntityLoader>();
            entityLoader.Owner = owner;
            AOTGameEntry.eventMgr.Subscribe(ShowEntitySuccessEventArgs.EventId, entityLoader.OnShowEntitySuccess);
            AOTGameEntry.eventMgr.Subscribe(ShowEntityFailureEventArgs.EventId, entityLoader.OnShowEntityFail);

            return entityLoader;
        }

        public void Clear()
        {
            Owner = null;
            dicSerial2Entity.Clear();
            dicCallback.Clear();
            AOTGameEntry.eventMgr.Unsubscribe(ShowEntitySuccessEventArgs.EventId, OnShowEntitySuccess);
            AOTGameEntry.eventMgr.Unsubscribe(ShowEntityFailureEventArgs.EventId, OnShowEntityFail);
        }

        private Dictionary<int, Action<Entity>> dicCallback;
        private Dictionary<int, Entity> dicSerial2Entity;

        private List<int> tempList;
        private List<Entity> _tempEntities;
    }
}

